#include <stdio.h>
#include <unistd.h>

#include <fcntl.h>

#include <signal.h>
#define BUF_SIZE 1
#define TIMEOUT 2


int 	sig_counter = 0;
char 	sig_buf[8];
int		child_pid;
int		isEof = 0;

sigset_t empty_mask;
sigset_t full_mask;

char getChar( char *ar)
{
	char buf = 0;
	int tmp = 1;
	int i;
	for ( i = 7; i >= 0; i--)
	{
		if ( ar[i] == 1)
		{
			buf += (char)tmp;
		}
		tmp*=2;
	}
	return buf;
}




void user1_Phandler( int i)
{	
	sigprocmask( SIG_BLOCK, &full_mask, NULL);
	
	sig_buf[ sig_counter] = 0;
	sig_counter++;
	
	kill( child_pid, SIGUSR1);
}
void user2_Phandler( int i)
{
	sigprocmask( SIG_BLOCK, &full_mask, NULL);
	
	sig_buf[ sig_counter] = 1;
	sig_counter++;
	
	kill( child_pid, SIGUSR2);
}

void sigchild_handler( int i)
{
	printf("\nSIG CHILD\n");
	exit(1);
}

void user1_Chandler( int i){
	//printf("\n\t\tChild :rcv user1\n");
	//fflush( NULL);
	
}
void user2_Chandler( int i){
	//printf("\n\t\tChild :rcv user2\n");
	//fflush( NULL);
}
void alarm_Chandler( int i){
	printf("\nTIMEOUT\n");
	fflush( NULL);
	exit(1);
}



/*
 * struct sigaction
 * {
 *	void     (*sa_handler)(int);
 *	void     (*sa_sigaction)(int, siginfo_t *, void *);
 *	sigset_t   sa_mask;
 *	int        sa_flags;
 *	void     (*sa_restorer)(void);
 };
 */

int main( int argc, char ** argv)
{
	sigemptyset( &empty_mask);
	
	sigemptyset( &full_mask );
	sigaddset  ( &full_mask, SIGUSR1);
	sigaddset  ( &full_mask, SIGUSR2);
	sigaddset  ( &full_mask, SIGCHLD);
	sigaddset  ( &full_mask, SIGALRM);
	
	if ( argc != 2)
	{
		printf("Wrong arguments\n");
		exit(1);
	}
	
	int fd = open( (char*)argv[1],O_RDONLY , 0644);
	if ( fd == -1)
	{
		printf("Can't open file: %s\n",(char*)argv[1]);
		exit(1);
	}
	///////////////////////////////////////
	sigset_t mask;
	struct sigaction sig_a;
	
	sigprocmask( SIG_BLOCK, &full_mask, NULL);
	
	int tmp = fork();
	if ( tmp == 0)
	{
		sig_a.sa_handler = user1_Chandler;
		sigaction( SIGUSR1, &sig_a, 0);
		
		sig_a.sa_handler = user2_Chandler;
		sigaction( SIGUSR2, &sig_a, 0);
		
		int ppid = getppid();
		//kill( ppid, SIGUSR1);
		
		char buf;
		int read_count = read( fd , &buf, BUF_SIZE);
		while ( read_count != 0)
		{
			int i;
			for ( i = 0; i < 8; i++)
			{
				sig_a.sa_handler = user1_Chandler;
				sigaction( SIGUSR1, &sig_a, 0);
				
				sig_a.sa_handler = user2_Chandler;
				sigaction( SIGUSR2, &sig_a, 0);
				
				sig_a.sa_handler = alarm_Chandler;
				sigaction( SIGALRM, &sig_a, 0);
				
				alarm( TIMEOUT);
				
				if ( buf & 128)
				{
					sigemptyset( &mask);
					sigaddset( &mask, SIGUSR1);
					
					kill( ppid, SIGUSR2);
					sigsuspend( &mask);
				}
				else
				{
					sigemptyset( &mask);
					sigaddset( &mask, SIGUSR2);
					
					kill( ppid, SIGUSR1);
					sigsuspend( &mask);
				}
				buf <<= 1;
			}
			read_count = read( fd, &buf, BUF_SIZE);
		}
		int i;
		for ( i = 0; i < 8; i++)
		{
			kill ( ppid, SIGUSR1);
			
			alarm( TIMEOUT);
			
			sigemptyset( &mask);
			sigaddset( &mask, SIGUSR2);
			
			sig_a.sa_handler = user1_Chandler;
			sigaction( SIGUSR1, &sig_a, 0);
			
			sig_a.sa_handler = user2_Chandler;
			sigaction( SIGUSR2, &sig_a, 0);
			
			sig_a.sa_handler = alarm_Chandler;
			sigaction( SIGALRM, &sig_a, 0);
			
			sigsuspend( &mask);		
			
		}
			
			exit(1);
	}
	else
	{
		child_pid = tmp;
		sigemptyset( &mask);
		//sigaddset( &mask, SIGUSR1);
		//sigaddset( &mask, SIGUSR2);
		
		char c;
		while ( !isEof)
		{
			sig_a.sa_handler = user1_Phandler;
			sigaction( SIGUSR1, &sig_a, 0);
			
			sig_a.sa_handler = user2_Phandler;
			sigaction( SIGUSR2, &sig_a, 0);
			
			sig_a.sa_handler = sigchild_handler;
			sigaction( SIGCHLD, &sig_a,0);
			
			sigsuspend( &empty_mask);
			
			if ( sig_counter == 8)
			{
				c = getChar( sig_buf);
				if ( c == 0)
				{
					printf("\nFinish\n");
					fflush( NULL);
					exit(1);
				}
				else
				{
					printf("%c", c);
				}
				
				sig_counter = 0;
			}
			
		}
	}
}
